/*
 * Aurora Store
 * Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
 *
 * Aurora Store is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * Aurora Store is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Aurora Store.  If not, see <http://www.gnu.org/licenses/>.
 *
 * taken from https://gitlab.com/AuroraOSS/AuroraStore/blob/master/app/src/main/java/com/aurora/store/utility/Root.java
 *
 */

package cm.aptoide.pt.install.installer;

import android.util.Log;
import cm.aptoide.pt.logger.Logger;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class Root {
  private static final String TAG = "Root";

  private Process mSuProcess;
  private boolean mIsAcquired = true;
  private boolean mIsTerminated;

  private BufferedWriter mWriter;
  private BufferedReader mReader;
  private BufferedReader mErrorReader;

  public Root() {
    try {
      mSuProcess = Runtime.getRuntime()
          .exec("su");
      mWriter = new BufferedWriter(new OutputStreamWriter(mSuProcess.getOutputStream()));
      mReader = new BufferedReader(new InputStreamReader(mSuProcess.getInputStream()));
      mErrorReader = new BufferedReader(new InputStreamReader(mSuProcess.getErrorStream()));
      exec("echo test");
    } catch (IOException e) {
      mIsAcquired = false;
      mIsTerminated = true;
      Log.w(TAG, "Unable to acquire root access: ");
      Log.w(TAG, e);
    }
  }

  public static boolean requestRoot() {
    try {
      Process root = Runtime.getRuntime()
          .exec("su -c exit");
      root.waitFor();
      return root.exitValue() == 0;
    } catch (Exception e) {
      Log.w(TAG, "Unable to acquire root access: ");
      Log.w(TAG, e);
      return false;
    }
  }

  public String exec(String command) {
    Logger.getInstance()
        .d("install", "executing command : " + command);
    try {
      StringBuilder sb = new StringBuilder();
      String breaker =
          "『BREAKER』";//Echoed after main command and used to determine when to stop reading from the stream
      mWriter.write(command + "\necho " + breaker + "\n");
      mWriter.flush();

      char[] buffer = new char[256];
      while (true) {
        sb.append(buffer, 0, mReader.read(buffer));

        int bi = sb.indexOf(breaker);
        if (bi != -1) {
          sb.delete(bi, bi + breaker.length());
          break;
        }
      }

      return sb.toString()
          .trim();
    } catch (Exception e) {
      mIsAcquired = false;
      mIsTerminated = true;
      Log.w(TAG, "Unable execute command: ");
      Log.w(TAG, e);
    }

    return null;
  }

  public String readError() {
    try {
      StringBuilder sb = new StringBuilder();
      String breaker = "『BREAKER』";
      mWriter.write("echo " + breaker + " >&2\n");
      mWriter.flush();

      char[] buffer = new char[256];
      while (true) {
        sb.append(buffer, 0, mErrorReader.read(buffer));

        int bi = sb.indexOf(breaker);
        if (bi != -1) {
          sb.delete(bi, bi + breaker.length());
          break;
        }
      }

      return sb.toString()
          .trim();
    } catch (Exception e) {
      mIsAcquired = false;
      mIsTerminated = true;
      Log.w(TAG, "Unable execute command: ");
      Log.w(TAG, e);
    }

    return null;
  }

  public void terminate() {
    if (mIsTerminated) return;

    mIsTerminated = true;
    mSuProcess.destroy();
  }

  public boolean isTerminated() {
    return mIsTerminated;
  }

  public boolean isAcquired() {
    return mIsAcquired;
  }
}
